﻿// "Therefore those skilled at the unorthodox
// are infinite as heaven and earth,
// inexhaustible as the great rivers.
// When they come to an end,
// they bagin again,
// like the days and months;
// they die and are reborn,
// like the four seasons."
// 
// - Sun Tsu,
// "The Art of War"

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using log4net.Core;
using log4net.Layout;

namespace Infrastructure.Logging.Layouts
{
    /// <summary>
    /// A Layout that renders only the Exception data from the logging event.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The data comes in three flavors:<br/>
    /// <b>Type:</b> the full type name of the exception (i.e. System.Exception)<br/>
    /// <b>Message:</b> the exception message<br/>
    /// <b>Full:</b> the full exception data as retrieved from exception.ToString().<br/>
    /// </para>
    /// <para>
    /// This Layout should only be used with appenders that utilize multiple
    /// layouts (e.g. <see cref="log4net.Appender.AdoNetAppender"/>).
    /// </para>
    /// </remarks>
    public class ServerDataLayout : LayoutSkeleton
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <remarks>
        /// <para>
        /// Constructs a ExceptionLayout
        /// </para>
        /// </remarks>
        public ServerDataLayout()
        {
            IgnoresException = false;

            try
            {
                var serverIp = Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault(address => address.AddressFamily != AddressFamily.InterNetworkV6);
                if (serverIp != null)
                    mServerIp = serverIp.ToString();
                else
                    LogManager.WriteTrace( "Failed to find server IP" );
            }
            catch( Exception ex )
            {
                LogManager.WriteTrace( "Failed to get server IP: " + ex.Message );
            }
        }

        #region Implementation of IOptionHandler

        /// <summary>
        /// Activate component options
        /// </summary>
        /// <remarks>
        /// <para>
        /// Part of the <see cref="IOptionHandler"/> component activation
        /// framework.
        /// </para>
        /// <para>
        /// This method does nothing as options become effective immediately.
        /// </para>
        /// </remarks>
        override public void ActivateOptions()
        {
            // nothing to do.
        }

        #endregion

        #region Override implementation of LayoutSkeleton

        /// <summary>
        /// Gets the exception text from the logging event
        /// </summary>
        /// <param name="writer">The TextWriter to write the formatted event to</param>
        /// <param name="loggingEvent">the event being logged</param>
        /// <remarks>
        /// <para>
        /// Write the exception string to the <see cref="TextWriter"/>.
        /// The exception string is retrieved from <see cref="LoggingEvent.GetExceptionString()"/>.
        /// </para>
        /// </remarks>
        override public void Format(TextWriter writer, LoggingEvent loggingEvent)
        {
            if (loggingEvent == null) throw new ArgumentNullException("loggingEvent");

            // depends on the output type write the data
            switch (mServerData)
            {
                case ServerData.IP:
                    if( mServerIp != null )
                        writer.Write( mServerIp );
                    break;
            }
        }

        #endregion


        #region Data members

        private ServerData mServerData;
        private readonly string mServerIp;

        /// <summary>
        /// get\set the output data type.
        /// Values: <see cref="ServerDataOutput"/>
        /// </summary>
        public string ServerDataOutput
        {
            get { return mServerData.ToString(); }
            set
            {
                try
                {
                    mServerData = (ServerData)Enum.Parse(typeof(ServerData), value, true);
                }
                catch (Exception)
                {
                    LogManager.WriteTrace("Failed setting OutputType [value: " + value + "]");
                    mServerData = ServerData.None;
                }
            }
        }

        #endregion
    }

    #region ExceptionOutput enum

    /// <summary>
    /// enum of the possible output data types.
    /// </summary>
    public enum ServerData
    {
        None, // in case of error reading config
        IP,
    }

    #endregion
}
